package com.redlion.hud;

import java.util.ArrayList;
import org.andengine.entity.IEntity;
import org.andengine.entity.modifier.IEntityModifier.IEntityModifierListener;
import org.andengine.entity.modifier.MoveModifier;
import org.andengine.entity.primitive.Rectangle;
import org.andengine.entity.scene.Scene;
import org.andengine.entity.sprite.AnimatedSprite;
import org.andengine.entity.sprite.Sprite;
import org.andengine.extension.physics.box2d.util.Vector2Pool;
import org.andengine.input.touch.TouchEvent;
import org.andengine.opengl.font.Font;
import org.andengine.opengl.texture.region.TextureRegion;
import org.andengine.opengl.texture.region.TiledTextureRegion;
import org.andengine.util.modifier.IModifier;
import org.andengine.util.modifier.ease.EaseCubicInOut;

import com.badlogic.gdx.math.Vector2;
import com.redlion.Game;
import com.redlion.GameActivity;
import com.redlion.weapon.CatalogAdapter;
import com.redlion.weapon.IdHolder;
import com.redlion.weapon.WeaponCatalog;

public class MyHUD {
	public static final float EASE_DURATION = 0.2f;
	public static final float EASE_DISTANCE = 0.5f;
	public static final int WEAPONSLOT_WIDTH = 200;
	public static final float WEAPONSLOT_HEIGHT = 100;
	private Sprite upperLeft;
	private Sprite upperRight;
	private Sprite lowerLeft;
	private Sprite lowerRight;
	private AnimatedSprite slotButton;
	public static boolean isShown;
	private ArrayList<Sprite> slots = new ArrayList<Sprite>();
	public Font mFont;
	private static Rectangle mCatalogshape;
	private ArrayList<OnCatalogItemClickListener> catalogListeners = new ArrayList<OnCatalogItemClickListener>();
	public SLOT clickedSlotPosition;
	private CatalogAdapter mLRadapter;
	private CatalogAdapter mLLadapter;
	private CatalogAdapter mULadapter;
	private CatalogAdapter mURadapter;
	private Sprite zoomButton;
	public static TextureRegion mCatalogItemBackground_TR;
	static ArrayList<Sprite> children = new ArrayList<Sprite>();
	private static GameActivity mBase;
	public static boolean activeAnimation = false;
	protected static CatalogAdapter currentAdapter;
	private static IEntityModifierListener animationListener = new IEntityModifierListener() {

		@Override
		public void onModifierStarted(IModifier<IEntity> pModifier, IEntity pItem) {
			activeAnimation = true;
		}

		@Override
		public void onModifierFinished(IModifier<IEntity> pModifier, IEntity pItem) {
			activeAnimation = false;
		}
	};

	public enum SLOT {
		UPPER_LEFT, UPPER_RIGHT, LOWER_LEFT, LOWER_RIGHT
	}

	public MyHUD(Font font, GameActivity pBase) {
		mFont = font;
		mBase = pBase;
	}

	public void createInterface(TextureRegion weaponSlot_TR, TiledTextureRegion toogleSlotsButton_TTR,
			TextureRegion catalogItemBackground_TR, Scene scene, Sprite planet) {

		mCatalogItemBackground_TR = catalogItemBackground_TR;
		createToogleButton(toogleSlotsButton_TTR, planet, scene);
		createZoomButton(scene, toogleSlotsButton_TTR);
		createWeaponSlots(weaponSlot_TR, scene, planet);
		createCatalaogContainer(scene);
		hideSlots();
	}

	private void createCatalaogContainer(Scene mScene) {
		mCatalogshape = new Rectangle(Game.CAMERA_WIDTH - WEAPONSLOT_WIDTH, 0, WEAPONSLOT_WIDTH, WEAPONSLOT_HEIGHT
				* WeaponCatalog.weapons.size(), Game.gameActivity.getVertexBufferObjectManager());
		mCatalogshape.setAlpha(0f);
		mScene.attachChild(mCatalogshape);
	}

	private void createZoomButton(Scene mScene, TiledTextureRegion pToogleToomButton_TTR) {
		zoomButton = new Sprite(20, 20, pToogleToomButton_TTR, Game.gameActivity.getVertexBufferObjectManager()) {
			@Override
			public boolean onAreaTouched(TouchEvent pSceneTouchEvent, float pTouchAreaLocalX, float pTouchAreaLocalY) {
				switch (pSceneTouchEvent.getAction()) {
				case TouchEvent.ACTION_DOWN:
					mBase.mZoomCamera.setZoomFactor(0.5f);
					break;
				case TouchEvent.ACTION_UP:
					mBase.mZoomCamera.setZoomFactor(1f);
					break;
				}
				return true;
			}
		};
		mScene.attachChild(zoomButton);
		mScene.registerTouchArea(zoomButton);
	}

	private void createWeaponSlots(TextureRegion texture, Scene mScene, Sprite sprite) {
		float px = sprite.getWidth() * 0.5f;
		float py = sprite.getHeight() * 0.5f;
		upperLeft = new Sprite(px - (texture.getWidth()), py - (texture.getHeight()), texture,
				Game.gameActivity.getVertexBufferObjectManager()) {
			@Override
			public boolean onAreaTouched(TouchEvent pSceneTouchEvent, float pTouchAreaLocalX, float pTouchAreaLocalY) {
				if (pSceneTouchEvent.isActionDown())
					if (isShown)
						slotULclick(this);
				return true;
			}
		};
		upperRight = new Sprite(px, py - (texture.getHeight()), texture, Game.gameActivity.getVertexBufferObjectManager()) {
			@Override
			public boolean onAreaTouched(TouchEvent pSceneTouchEvent, float pTouchAreaLocalX, float pTouchAreaLocalY) {
				if (pSceneTouchEvent.isActionDown())
					if (isShown)
						slotURClick(this);
				return true;
			}
		};
		upperRight.setRotation(90);
		lowerLeft = new Sprite(px - (texture.getWidth()), py, texture, Game.gameActivity.getVertexBufferObjectManager()) {
			@Override
			public boolean onAreaTouched(TouchEvent pSceneTouchEvent, float pTouchAreaLocalX, float pTouchAreaLocalY) {
				if (pSceneTouchEvent.isActionDown())
					if (isShown)
						slotLLclick(this);
				return true;
			}
		};
		lowerLeft.setRotation(270);
		lowerRight = new Sprite(px, py, texture, Game.gameActivity.getVertexBufferObjectManager()) {
			@Override
			public boolean onAreaTouched(TouchEvent pSceneTouchEvent, float pTouchAreaLocalX, float pTouchAreaLocalY) {
				if (pSceneTouchEvent.isActionDown())
					if (isShown)
						slotLRclick(this);
				return true;
			}
		};
		lowerRight.setRotation(180);
		sprite.attachChild(upperLeft);
		sprite.attachChild(upperRight);
		sprite.attachChild(lowerLeft);
		sprite.attachChild(lowerRight);
		mScene.registerTouchArea(upperLeft);
		mScene.registerTouchArea(upperRight);
		mScene.registerTouchArea(lowerLeft);
		mScene.registerTouchArea(lowerRight);
		slots.add(lowerLeft);
		slots.add(lowerRight);
		slots.add(upperLeft);
		slots.add(upperRight);
	}

	private void createToogleButton(TiledTextureRegion mSlotButtonRegion, Sprite planet, Scene scene) {
		float px = planet.getWidth() / 2;
		float py = planet.getHeight() / 2;
		slotButton = new AnimatedSprite(px - (mSlotButtonRegion.getWidth() / 2), py - (mSlotButtonRegion.getHeight() / 2),
				mSlotButtonRegion, Game.gameActivity.getVertexBufferObjectManager()) {

			@Override
			public boolean onAreaTouched(TouchEvent pSceneTouchEvent, float pTouchAreaLocalX, float pTouchAreaLocalY) {
				if (pSceneTouchEvent.isActionDown()) {
					if (!isShown)
						showSlots();
					else
						hideSlots();
				}
				return true;
			}
		};
		planet.attachChild(slotButton);
		scene.registerTouchArea(slotButton);
	}

	public void showSlots() {
		upperLeft.setIgnoreUpdate(false);
		upperLeft.setVisible(true);
		upperRight.setIgnoreUpdate(false);
		upperRight.setVisible(true);
		lowerLeft.setIgnoreUpdate(false);
		lowerLeft.setVisible(true);
		lowerRight.setIgnoreUpdate(false);
		lowerRight.setVisible(true);
		slotButton.setCurrentTileIndex(1);
		isShown = true;
	}

	public void hideSlots() {
		upperLeft.setIgnoreUpdate(true);
		upperLeft.setVisible(false);
		upperRight.setIgnoreUpdate(true);
		upperRight.setVisible(false);
		lowerLeft.setIgnoreUpdate(true);
		lowerLeft.setVisible(false);
		lowerRight.setIgnoreUpdate(true);
		lowerRight.setVisible(false);
		slotButton.setCurrentTileIndex(0);
		mCatalogshape.setIgnoreUpdate(true);
		mCatalogshape.setVisible(false);
		resetPositions();
		isShown = false;
	}

	private void resetPositions() {
		for (Sprite slot : slots) {
			if (slot.getUserData() != null) {
				Float[] coords = (Float[]) slot.getUserData();
				slot.setPosition(coords[0], coords[1]);
				slot.setUserData(null);
			}
		}
	}

	private void handleSlotClick(Sprite clickedSlot, SLOT position) {
		if (!activeAnimation) {
			for (Sprite slot : slots) {
				if (!slot.equals(clickedSlot) && slot.getUserData() != null)
					moveSlotIn(slot);
			}
			if (clickedSlot != null && clickedSlot.getUserData() == null)
				moveSlotOut(clickedSlot, position);
			else
				moveSlotIn(clickedSlot);
		}
	}

	protected void slotLRclick(Sprite sprite) {
		handleSlotClick(sprite, SLOT.LOWER_RIGHT);
	}

	protected void slotLLclick(Sprite sprite) {
		handleSlotClick(sprite, SLOT.LOWER_LEFT);
	}

	protected void slotURClick(Sprite sprite) {
		handleSlotClick(sprite, SLOT.UPPER_RIGHT);
	}

	protected void slotULclick(Sprite sprite) {
		handleSlotClick(sprite, SLOT.UPPER_LEFT);
	}

	private void moveSlotOut(Sprite sprite, SLOT position) {
		sprite.setUserData(new Float[] { sprite.getX(), sprite.getY() });
		Vector2 dir = Vector2Pool.obtain(sprite.getX() + sprite.getWidth() / 2, sprite.getY() + sprite.getHeight() / 2)
				.sub(slotButton.getX() + slotButton.getWidth() / 2, slotButton.getY() + slotButton.getHeight() / 2).mul(EASE_DISTANCE);
		Vector2 temp = Vector2Pool.obtain(sprite.getX(), sprite.getY()).add(dir);

		sprite.registerEntityModifier(new MoveModifier(EASE_DURATION, sprite.getX(), temp.x, sprite.getY(), temp.y, animationListener,
				EaseCubicInOut.getInstance()));
		Vector2Pool.recycle(temp);
		Vector2Pool.recycle(dir);
		mCatalogshape.setIgnoreUpdate(false);
		mCatalogshape.setVisible(true);
		updateCatalogContent(position);
		clickedSlotPosition = position;
	}

	private void moveSlotIn(Sprite sprite) {
		Float[] coords = (Float[]) sprite.getUserData();
		sprite.registerEntityModifier(new MoveModifier(EASE_DURATION, sprite.getX(), coords[0], sprite.getY(), coords[1],
				animationListener, EaseCubicInOut.getInstance()));
		sprite.setUserData(null);
		mCatalogshape.setIgnoreUpdate(true);
		mCatalogshape.setVisible(false);
	}

	private void updateCatalogContent(final SLOT position) {
		final CatalogAdapter ca;
		switch (position) {
		case LOWER_RIGHT:
			ca = mLRadapter;
			break;
		case LOWER_LEFT:
			ca = mLLadapter;
			break;
		case UPPER_LEFT:
			ca = mULadapter;
			break;
		case UPPER_RIGHT:
			ca = mURadapter;
			break;
		default:
			return;
		}
		updateCatalogContainer(ca);
	}

	public static void updateCatalogContainer(final CatalogAdapter adapter) {
		mBase.runOnUpdateThread(new Runnable() {
			@Override
			public void run() {
				children.clear();
				for (int i = 0; i < adapter.getCatalogItemSize(); i++) {
					Sprite s;
					if (i < mCatalogshape.getChildCount())
						s = adapter.getCatalogItem(i, (Sprite) mCatalogshape.getChildByIndex(i));
					else
						s = adapter.getCatalogItem(i, null);
					s.setUserData(adapter.getItem(i));
					children.add(s);
					currentAdapter = adapter;
				}
				mCatalogshape.detachChildren();
				for (Sprite sprite : children) {
					mCatalogshape.attachChild(sprite);
				}
			}
		});

	}

	public void registerListener(OnCatalogItemClickListener listener) {
		catalogListeners.add(listener);
	}

	public void removeListener(OnCatalogItemClickListener listener) {
		catalogListeners.remove(listener);
	}

	public void bindCatalogEntryToSlot(SLOT position, CatalogAdapter adapter) {
		switch (position) {
		case LOWER_RIGHT:
			mLRadapter = adapter;
			break;
		case LOWER_LEFT:
			mLLadapter = adapter;
			break;
		case UPPER_LEFT:
			mULadapter = adapter;
			break;
		case UPPER_RIGHT:
			mURadapter = adapter;
			break;
		default:
			break;
		}
	}

	public static void notifyOnCatalogEntryClick(WeaponEntrySprite weaponEntrySprite) {
		if (currentAdapter != null && weaponEntrySprite.getUserData() instanceof IdHolder) {
			currentAdapter.onItemClick((IdHolder) weaponEntrySprite.getUserData());
			updateCatalogContainer(currentAdapter);
		}
	}
}
